﻿using ApiGateway.Config;
using ApiGateway.Helper;
using ApiGateway.Interface;
using RpcHelper;
using RpcHelper.Config;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;

namespace ApiGateway.PlugIn
{
    /// <summary>
    /// 请求接口限流插件
    /// </summary>
    internal class NodeLimitPlugIn : BasicPlugIn, INodeLimitPlugIn
    {
        private readonly ConcurrentDictionary<string, ILimit> _NodeLimit = new ConcurrentDictionary<string, ILimit>();

        private NodeLimitConfig _Config;
        private Timer _Timer;

        public override bool IsEnable => this._Config.LimitType != GatewayLimitType.不启用;

        public NodeLimitPlugIn(IConfigCollect configService) : base("NodeLimit")
        {
            NodeLimitConfig config = configService.GetValue<NodeLimitConfig>("gateway:nodeLimit", new NodeLimitConfig());
            if (config.Excludes == null)
            {
                config.Excludes = new string[0];
            }
            if (config.Limits == null)
            {
                config.Limits = new string[0];
            }
            this._Config = config;
            configService.RefreshEvent += this._Init;
        }

        private void _Refresh(object state)
        {
            if (!this._NodeLimit.IsEmpty)
            {
                int now = HeartbeatTimeHelper.HeartbeatTime;
                KeyValuePair<string, ILimit>[] limits = this._NodeLimit.ToArray();
                foreach (KeyValuePair<string, ILimit> i in limits)
                {
                    ILimit limit = i.Value;
                    limit.Refresh(now);
                }
            }
        }
        private void _Init(IConfigCollect server, string name)
        {
            if (name == "gateway:nodeLimit" || name.StartsWith("gateway:nodeLimit:"))
            {
                NodeLimitConfig config = server.GetValue<NodeLimitConfig>("gateway:nodeLimit", new NodeLimitConfig());
                if (config.LimitType == GatewayLimitType.不启用 && this._Config.LimitType != GatewayLimitType.不启用)
                {
                    this._Config = config;
                    base._ChangeEvent();
                }
                else if (config.LimitType != GatewayLimitType.不启用 && this._Config.LimitType == GatewayLimitType.不启用)
                {
                    this._Config = config;
                    base._ChangeEvent();
                }
                else if (this._Config.LimitType != config.LimitType && !this._NodeLimit.IsEmpty)
                {
                    this._Config = config;
                    this._NodeLimit.Clear();
                }
                else
                {
                    this._Config = config;
                }
            }
        }
        protected override void _InitPlugIn()
        {
            if (this._Config.LimitType == GatewayLimitType.不启用)
            {
                return;
            }
            if (this._Timer == null)
            {
                this._Timer = new Timer(this._Refresh, null, 1000, 1000);
            }
        }

        protected override void _Dispose()
        {
            if (this._Config.LimitType == GatewayLimitType.不启用)
            {
                this._Timer?.Dispose();
                this._NodeLimit.Clear();
                this._Timer = null;
            }
        }
        public bool IsLimit(string node)
        {
            if (!this._Config.CheckIsLimit(node))
            {
                return false;
            }
            else if (this._NodeLimit.TryGetValue(node, out ILimit limit))
            {
                return limit.IsLimit();
            }
            else
            {
                limit = LimitHelper.GetLimit(this._Config);
                this._NodeLimit.TryAdd(node, limit);
                return limit.IsLimit();
            }

        }
    }
}
